#include "Config.h"
#include "PatternList.h"
#include "Seq.h"

unsigned char InterpolatePixelDirection( int frame_no, int x, int y );

#define ABS(x) ((x)>0 ? (x) : (-(x)))
#define MIN(a, b) ( (a)<(b) ? (a) : (b) )
#define SAME5(a, b, c, d, e) ( (a)==(b) && (b)==(c) && (c)==(d) && (d)==(e) )
#define SAME4(a, b, c, d) ( (a)==(b) && (b)==(c) && (c)==(d) )
#define SAME3(a, b, c) ( (a)==(b) && (b)==(c) )
#define SAME2(a, b) ( (a)==(b) )
#define NSAME(a, b) ( (a)!=(b) )

int DIFF2(int a, int b)
{
	int avg = (a+b+1)/2;
	int ret = 0;
	ret += ABS(a-avg);
	ret += ABS(b-avg);
	ret = (ABS(ret)+1)*100/2;
	return ret;
}

int DIFF3(int a, int b, int c)
{
	int avg = (a+b+c+1)/3;
	int ret = 0;
	ret += ABS(a-avg);
	ret += ABS(b-avg);
	ret += ABS(c-avg);
	ret = (ABS(ret)+1)*100/3;
	return ret;
}

int DIFF4(int a, int b, int c, int d)
{
	int avg = (a+b+c+d+2)/4;
	int ret = 0;
	ret += ABS(a-avg);
	ret += ABS(b-avg);
	ret += ABS(c-avg);
	ret += ABS(d-avg);
	ret = (ABS(ret)+2)*100/4;
	return ret;
}

int DIFF5(int a, int b, int c, int d, int e)
{
	int avg = (a+b+c+d+e+2)/4;
	int ret = 0;
	ret += ABS(a-avg);
	ret += ABS(b-avg);
	ret += ABS(c-avg);
	ret += ABS(d-avg);
	ret += ABS(e-avg);
	ret = (ABS(ret)+2)*100/5;
	return ret;
}



void InterpolateWithDirection()
{
	CPatternList * pattern_list = CPatternList::GetInstance();

	CConfig * config = CConfig::GetConfig();

	CSeq * seq = config->seq;
	int pattern_count = 0; 
	int unpattern_count = 0;

	unsigned char ref_pixel[6];
	char ref_coff[6] = { 1, -5, 20, 20, -5, 1 };
	char ref_x_offset[6] = { -5, -3, -1, 1, 3, 5 };
	int sum = 0;

	for ( int frame=0; frame<seq->m_iFrameCount; frame++ )
	{
		for( int y=VERTICAL_SKIP_COUNT; y<seq->m_iHeight-VERTICAL_SKIP_COUNT; y++ )
		{
			for ( int x=HORIZONTAL_SKIP_COUNT; x<seq->m_iWidth-HORIZONTAL_SKIP_COUNT; x+=2 )
			{
				seq->m_ppIntPixelArray[frame][y * seq->m_iWidth + x] = InterpolatePixelDirection( frame, x, y );
				
				// cout << "X: " << x << " Y: " << y << endl;
			}
		}
	}

}

unsigned char InterpolatePixelDirection( int frame_no, int x, int y )
{
	unsigned char * reco = CConfig::GetConfig()->seq->m_ppIntPixelArray[frame_no];
	int img_width = CConfig::GetConfig()->seq->m_iWidth;
	int img_height = CConfig::GetConfig()->seq->m_iHeight;

	unsigned char a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15;
	int max, min; max = 0; min = 100000;
	a0 = reco[(y+1)*img_width+(x-1)]; if (a0>max) max=a0; if (a0<min) min=a0;
	a1 = reco[(y  )*img_width+(x-1)]; if (a1>max) max=a1; if (a1<min) min=a1;
	a2 = reco[(y-1)*img_width+(x-1)]; if (a2>max) max=a2; if (a2<min) min=a2;
	a3 = reco[(y-1)*img_width+(x  )]; if (a3>max) max=a3; if (a3<min) min=a3;
	a4 = reco[(y-1)*img_width+(x+1)]; if (a4>max) max=a4; if (a4<min) min=a4;
	a5 = reco[(y  )*img_width+(x+1)]; if (a5>max) max=a5; if (a5<min) min=a5;
	a6 = reco[(y+1)*img_width+(x+1)]; if (a6>max) max=a6; if (a6<min) min=a6;
	a7  = reco[(y  )*img_width+(x-2)]; if (a7>max) max=a7; if (a7<min) min=a7;
	a8  = reco[(y-1)*img_width+(x-2)]; if (a8>max) max=a8; if (a8<min) min=a8;
	a9  = reco[(y-2)*img_width+(x-2)]; if (a9>max) max=a9; if (a9<min) min=a9;
	a10 = reco[(y-2)*img_width+(x-1)]; if (a10>max) max=a10; if (a10<min) min=a10;
	a11 = reco[(y-2)*img_width+(x  )]; if (a11>max) max=a11; if (a11<min) min=a11;
	a12 = reco[(y-2)*img_width+(x+1)]; if (a12>max) max=a12; if (a12<min) min=a12;
	a13 = reco[(y-2)*img_width+(x+2)]; if (a13==0) a13=a12; if (a13>max) max=a13; if (a13<min) min=a13;
	a14 = reco[(y-1)*img_width+(x+2)]; if (a14==0) a14=a4; if (a14>max) max=a14; if (a14<min) min=a14;
	a15 = reco[(y  )*img_width+(x+2)]; if (a15==0) a15=a5; if (a15>max) max=a15; if (a15<min) min=a15;

	int avg = (a0+a1+a2+a3+a4+a5+a6+a7+a8+a9+a10+a11+a12+a13+a14+a15+8)/16;

	int v = 0;
	int tv = 0;
	int b0, b1, b2, b3, b4, b5, b6, inner = 0;
	int b7, b8, b9, b10, b11, b12, b13, b14, b15, outer = 0;
	inner = (a0>avg) ? inner|1 : inner;		b0 = (a0>avg) ? 1 : 0;
	inner = (a1>avg) ? inner|2 : inner;		b1 = (a1>avg) ? 1 : 0;
	inner = (a2>avg) ? inner|4 : inner;		b2 = (a2>avg) ? 1 : 0;
	inner = (a3>avg) ? inner|8 : inner;		b3 = (a3>avg) ? 1 : 0;
	inner = (a4>avg) ? inner|16 : inner;	b4 = (a4>avg) ? 1 : 0;
	inner = (a5>avg) ? inner|32 : inner;	b5 = (a5>avg) ? 1 : 0;
	inner = (a6>avg) ? inner|64 : inner;	b6 = (a6>avg) ? 1 : 0;
	outer = (a7 >avg) ? outer|1 : outer;		b7 = (a7>avg) ? 1 : 0;
	outer = (a8 >avg) ? outer|2 : outer;		b8 = (a8>avg) ? 1 : 0;
	outer = (a9 >avg) ? outer|4 : outer;		b9 = (a9>avg) ? 1 : 0;
	outer = (a10>avg) ? outer|8 : outer;		b10 = (a10>avg) ? 1 : 0;
	outer = (a11>avg) ? outer|16 : outer;	b11 = (a11>avg) ? 1 : 0;
	outer = (a12>avg) ? outer|32 : outer;	b12 = (a12>avg) ? 1 : 0;
	outer = (a13>avg) ? outer|64 : outer;	b13 = (a13>avg) ? 1 : 0;
	outer = (a14>avg) ? outer|128 : outer;	b14 = (a14>avg) ? 1 : 0;
	outer = (a15>avg) ? outer|256 : outer;	b15 = (a15>avg) ? 1 : 0;

	//int line, minline, line0, line1, line2, line3, line4, line5, line6, line7;
	int bshow = 0;
	tv = ( -a7 + 5*a1 + 5*a5 - a15 + 4 ) / 8;
//	return iClip3(0,255,tv);
	if (max-min<20) {
		v = tv;
	} else {
		//line=0; minline = 100000;
		//line0 = DIFF4(a7, a1, a5, a15); if (line0<minline) { minline=line0; line=0; }
		//line1 = (DIFF4(a7, a1, a4, a14) + DIFF3(a0, a5, a15) + 1)/2; if (line1<minline) { minline=line1; line=1; }
		//line2 = DIFF3(a0, a4, a13); if (line2<minline) { minline=line2; line=2; }
		//line3 = (DIFF2(a4, a12) + DIFF3(a0, a3, a11) + 1)/2; if (line3<minline) { minline=line3; line=3; }
		//line4 = (DIFF2(a3, a11) + MIN(DIFF4(a0, a1, a2, a10),DIFF4(a6, a5, a4, a12)) + 1)/2;  if (line4<minline) { minline=line4; line=4; }
		//line5 = (DIFF2(a2, a10) + DIFF3(a6, a3, a11) + 1)/2; if (line5<minline) { minline=line5; line=5; }
		//line6 = DIFF3(a6, a2, a9); if (line6<minline) { minline=line6; line=6; }
		//line7 = (DIFF4(a8, a2, a5, a15) + DIFF3(a7, a1, a6) + 1)/2; if (line7<minline) { minline=line7; line=7; }

		// x x x
		// x   .
		// x   x
		if ( inner==0x20 || inner==0x5F ) {
			if ( SAME3(b2, b8, b14) ) {
				v = tv;
			} else if ( SAME3(b3, b10, b11) || SAME3(b3, b11, b12) ) {
				if ( SAME2(b5, b15) && SAME2(b1, b7) ) {
					v = tv;
				} else if ( NSAME(b5, b15) ) {
					v = ( a1 + a3 + a5 + 1 ) / 3;
				} else {
					v = ( -a11 + 3*a3 + a1 + a5 + 2) / 4;
				}
			} else {
				v = tv;///( a1 + a5 + 1 ) / 2;
			}
			// x x x
			// .   x
			// x   x
		} else if ( inner==0x02 || inner==0x7D ) {
			if ( SAME3(b2, b8, b14) ) {
				v = tv;
			} else if ( SAME3(b3, b10, b11) || SAME3(b3, b11, b12) ) {
				if ( SAME2(b5, b15) && SAME2(b1, b7) ) {
					v = tv;
				} else if ( NSAME(b1, b7) ) {
					v = ( a1 + a3 + a5 + 1 ) / 3;
				} else {
					v = ( -a11 + 3*a3 + a1 + a5 + 2) / 4;
				}
			} else {
				v = tv;
			}
			// x x .
			// x   .
			// x   .
		} else if ( inner==0x70 || inner==0x0F ) {
			if ( SAME3(b3, b10, b11) && SAME2(b4, b12) ) {
				v = a3 + (a5-a4+a1-a2)/2;
			} else {
				v = tv;
			}
			// . x x
			// .   x
			// .   x
		} else if ( inner==0x78 || inner==0x07 ) {
			if ( SAME3(b3, b11, b12) && SAME2(b2, b10) ) {
				v = a3 + (a5-a4+a1-a2)/2;
			} else {
				v = tv;
			}
			// x x x
			// x   x
			// .   .
		} else if ( inner==0x3E || inner==0x41 ) {
			if ( SAME3(b3, b10, b11) || SAME3(b3, b11, b12) ) {
				v = ( 1*tv + a3 + (a5-a4+a1-a2)/2 + 1 ) / 2;
			} else {
				v = tv;
			}
			// x x .
			// x   .
			// x   x
		} else if ( inner==0x30 || inner== 0x4F ) {
			if ( SAME5(b4, b12, b13, b14, b15) && SAME2(b3, b11) ) {
				v = a3 + (a5-a4+a1-a2)/2;
			} else {
				v = tv;
			}
			// . x x
			// .   x
			// x   x
		} else if ( inner==0x06 || inner== 0x79 ) {
			if ( SAME5(b2, b7, b8, b9, b10) && SAME2(b3, b11) ) {
				v = a3 + (a5-a4+a1-a2)/2;
			} else {
				v = tv;
			}
		} else {
			v = tv;
		}
	}

	unsigned char result;
	result = v;
	if ( v < 0 ) result = 0;
	if ( v > 255 ) result = 255;
	return result;
}
